from update.tools.w_deployment_send import DEHandler
from git import *
from socketserver import BaseRequestHandler, TCPServer, ThreadingTCPServer

import os
import time
import configparser
import json
import traceback
import shutil
import zipfile
import threading
import zmq
import sys

#大写字母不转换
class myconf(configparser.ConfigParser):
    def __init__(self):
        super(myconf, self).__init__()
        self._comment_prefixes = tuple(('#', ';', '//') or ())

    def optionxform(self, optionstr):
        return optionstr

class deployment_zcell(threading.Thread):
    def __init__(self, module_list):
        super(deployment_zcell, self).__init__()
        self.context = zmq.Context()
        self.config_file = r'D:\pycharms\django\operationsb\update\tools\config.ini'
        self.config = myconf()
        self.config.read(self.config_file)
        self.Equipment_file = r'D:\pycharms\django\operationsb\update\tools\Equipment.ini'
        self.Equipment = myconf()
        self.Equipment.read(self.Equipment_file)
        self.deployment_file = self.config.get('service_side','deployment_file')
        self.git_file = self.config.get('service_side','git_file')
        self.zcell_name = ''
        self.module_file = ''
        self.send_zip_status = True
        self.return_code = 1
        self.module_list = module_list

    def deployment_start(self, module):
        for i in module:
            self.deployment_create(i)

    def deployment_write(self, writefile):
        #编辑ini文件
        for file in writefile:
            other_config = myconf()
            other_file = os.path.join(self.module_file,file[0])
            other_config.read(other_file)
            for i in file[2].split('|'):
                k,v = i.split('=')
                other_config.set(file[1],k,v)
            fh = open(other_file,"w")
            other_config.write(fh)
            fh.close()
        exe_name = self.module_file.split('\\').pop() + '.exe'
        lists = os.listdir(self.module_file)
        for item in lists:
            if item.endswith('exe'):
                old_exe_file = os.path.join(self.module_file, item)
                new_exe_file = os.path.join(self.module_file, exe_name)
                shutil.move(old_exe_file, new_exe_file)

    def deployment_create(self, module):
        self.zcell_name = module["zcellname"]
        modulename = module["modulename"]
        version = module["version"]
        filename = module["filename"]
        zcell_git_name = self.Equipment.get('Equipment1',modulename)
        zcell_git_file1 = self.git_file
        zcell_git_file2 = os.path.join(zcell_git_file1, zcell_git_name)
        file = self.deployment_file
        self.module_file = os.path.join(file, filename)
        try:
            os.mkdir(self.module_file)
            #切换当前分支的标签
            repo = Repo(zcell_git_file2)
            repo.git.checkout(version)
            repo.close()
            a = os.listdir(zcell_git_file2)
            for i in a:
                b = os.path.join(zcell_git_file2, i)
                c = os.path.join(self.module_file,'Plugin')
                if i == 'Plugin':
                    shutil.copytree(b,c)
                elif i != '.git' and i != 'README.md':
                    shutil.copy(b,self.module_file)
                else:
                    pass
            #修改文件并压缩成zip包
            self.deployment_write(module["configuration"])
            self.deployment_zip()

        except FileExistsError as e:
            print('filename名称重复: %s' % e)
            serv.shutdown()
            self.send_zip_status = False
            self.return_code = 1
            sys.exit(1)
        except InvalidGitRepositoryError as e:
            print('git目录出错，没有数据: %s' % e)
            serv.shutdown()
            self.send_zip_status = False
            self.return_code = 1
            sys.exit(1)
        except:
            traceback.print_exc()
            serv.shutdown()
            self.send_zip_status = False
            self.return_code = 1
            sys.exit(1)

    def deployment_zip(self):
        f = self.module_file + '.zip'
        pre_len = len(self.module_file)
        zipf = zipfile.ZipFile(f, 'w')
        for parent, dirnames, filenames in os.walk(self.module_file):
            for filename in filenames:
                pathfile = os.path.join(parent, filename)
                arcname = pathfile[pre_len:].strip(os.path.sep)
                zipf.write(pathfile, arcname, compress_type=zipfile.ZIP_DEFLATED)
        zipf.close()
        return

    def pub_zcell_all(self,zcell_list):
        pub_socket = self.context.socket(zmq.PUB)
        pub_port = self.config.get('ports','d_pub_port')
        pub_socket.bind("tcp://*:%s" % pub_port)
        sleep_time = 1
        while self.send_zip_status:
            time.sleep(sleep_time)
            for i in zcell_list:
                for k,v in i.items():
                    msg = k + "|" + str(v)
                    print("->", msg)
                    pub_socket.send_string(msg)
            sleep_time += 0.5

    def contact_zip(self, module):
        # thread_port = self.config.get('ports', 'thread_logo_1')
        deployment_list = []
        for i in module:
            deployment_list.append(i["filename"])
        already_deployment_list = []
        not_deployment_list = []
        socket_port = self.config.get('ports','d_rep_port')
        initial_date = time.mktime(time.localtime())
        timeout = initial_date + 180
        while self.send_zip_status:
            # if timeout < time.mktime(time.localtime()):
            #     print('等待超时，进程结束')
            #     serv.shutdown()
            #     self.send_zip_status = False
            #     sys.exit(1)
            print('开始接受消息')
            thread_socket = self.context.socket(zmq.REP)
            thread_socket.bind("tcp://*:%s" % socket_port)
            poll = zmq.Poller()
            poll.register(thread_socket, zmq.POLLIN)
            socks = dict(poll.poll(60000))
            if socks.get(thread_socket) == zmq.POLLIN:
                lists = thread_socket.recv_string()
                thread_socket.close()
                for i in eval(lists):
                    already_deployment_list.append(i)
                not_deployment_list = [item for item in deployment_list if item not in already_deployment_list]
                error_deployment_list = [item for item in already_deployment_list if item not in deployment_list]

                if len(not_deployment_list) == 0:
                    print('关闭所有线程')
                    serv.shutdown()
                    self.send_zip_status = False
                    self.return_code = 0
                    sys.exit(0)
                elif len(error_deployment_list) != 0:
                    print('无法匹配到对应的模块名称，进程结束')
                    serv.shutdown()
                    self.send_zip_status = False
                    self.return_code = 1
                    sys.exit(1)
            else:
                print("超时")
                print(not_deployment_list, '============')
                print(already_deployment_list, '=============')
                serv.shutdown()
                self.return_code = 1
                sys.exit(1)

    def deployment_zip_send(self):
        #NWORKERS = 1
        socket_port = int(self.config.get('deployment','socket_port'))
        global serv
        serv = TCPServer(('', socket_port), DEHandler)
        #for n in range(NWORKERS):
        t = threading.Thread(target=serv.serve_forever)
        #t.daemon = True
        t.start()
        print('=================1')
        serv.serve_forever(poll_interval=0.5)
        print('=======================')

    def deployment_threading(self, module):
        zcell_all_list = []
        zcell_one_json = {}
        for i in module:
            try:
                one_list = zcell_one_json[i["zcellname"]]
                one_list.append(i["filename"])
            except:
                zcell_one_json[i["zcellname"]] = []
                one_list = zcell_one_json[i["zcellname"]]
                one_list.append(i["filename"])
            try:
                zcell_all_list.index(zcell_one_json)
            except:
                zcell_all_list.append(zcell_one_json)
        t2 = threading.Thread(target=self.deployment_zip_send)
        t2.start()
        t1 = threading.Thread(target=self.deployment_start, args=(module,))
        t1.start()
        t1.join()
        t3 = threading.Thread(target=self.pub_zcell_all, args=(zcell_all_list,))
        t4 = threading.Thread(target=self.contact_zip, args=(module, ))
        t3.start()
        t4.start()

    def run(self):
        self.deployment_threading(self.module_list)

if __name__ == '__main__':

    # a.git_version()
    module_list = [{"zcellname":"zcell02","ip":"127.0.0.1","modulename":"AS-K41103","version":"v1.0","filename":"KLX0300101","configuration":[["Startup.ini","Config","Path=KLX0300101.exe"],["AlarmSVR.ini","Config","Node=KLX0300101"]]}]
    #module_list = [{"zcellname":"zcell01","ip":"127.0.0.1","modulename":"AS-K41103","version":"v1.0","filename":"KLX0300101","configuration":[["Startup.ini","Config","Path=KLX0300101.exe"],["AlarmSVR.ini","Config","Node=KLX0300101"]]},{"zcellname":"zcell01","ip":"127.0.0.1","modulename":"DVM-K15001","version":"v1.0","filename":"KLXV0100101","configuration":[["Startup.ini","Config","Path=KLXV0100101.exe"],["Config.ini","videoSVR","Node=KLXV0100101"],["Plugin/plugin.ini", "Account","username=work@gmaple.cn|password=123456"]]}]
    # module_list = [{"zcellname":"zcell01","ip":"127.0.0.1","modulename":"AS-K41103","version":"v1.0","filename":"KLX0300101","configuration":[["Startup.ini","Config","Path=KLX0300101.exe"],["AlarmSVR.ini","Config","Node=KLX0300101"]]},{"zcellname":"zcell01","ip":"127.0.0.1","modulename":"DVM-K15001","version":"v1.0","filename":"KLXV0100101","configuration":[["Startup.ini","Config","Path=KLXV0100101.exe"],["Config.ini","videoSVR","Node=KLXV0100101"],["Plugin/plugin.ini", "Account","username=work@gmaple.cn|password=123456"]]}, {"zcellname":"zcell02","ip":"192.168.1.104","modulename":"AS-K41401","version":"v1.0","filename":"KL0100102","configuration":[["Startup.ini","Config","Path=KL0100102.exe"],["AlarmSVR.ini","Config","Node=KL0100102"]]}]
    a = deployment_zcell(module_list)
    a.start()
    a.join()
    print(a.return_code)
